package com.ysstech.reportworld.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ysstech.common.enums.YssEnum;
import com.ysstech.common.exception.BusinessException;
import com.ysstech.common.service.DicvalueService;
import com.ysstech.common.util.ZipUtil;
import com.ysstech.common.util.fileutil.FileWriterUtil;
import com.ysstech.common.util.resultutil.RestResult;
import com.ysstech.common.util.resultutil.ResultGenerator;
import com.ysstech.reportworld.entity.*;
import com.ysstech.reportworld.enums.ReportWorldEnum;
import com.ysstech.reportworld.enums.ReportWorldFileNameEnum;
import com.ysstech.reportworld.enums.ReportWorldStatusEnum;
import com.ysstech.reportworld.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileWriter;
import java.nio.file.Paths;
import java.util.*;

@Slf4j
@Service
public class UpgradeToolsZipServiceImpl implements UpgradeToolsZipService {

    @Autowired
    private ModularService modularService;
    @Autowired
    private ReportService reportService;
    @Autowired
    private TableService tableService;
    @Autowired
    private TableDetailService tableDetailService;
    @Autowired
    private DataSqlService dataSqlService;
    @Autowired
    public DemandBugInfoService demandBugInfoService;
    @Autowired
    private DatabaseService databaseService;
    @Autowired
    private CompareconfigService compareconfigService;
    @Autowired
    private DicvalueService dicvalueService;
    @Autowired
    private DataCustomerService dataCustomerService;
    @Autowired
    private DataReportService dataReportService;
    @Autowired
    private DataModularService dataModularService;
    @Autowired
    private DataDemandBugService dataDemandBugService;
    @Autowired
    private DatabaseConfigService databaseConfigService;
    @Autowired
    private TableIndexedService tableIndexedService;
    @Value("${file.uploadFolder}")
    private String uploadFolder;
    @Value("${file.uploadFolder.soure}")
    private String uploadFolderSoure;
    @Value("${file.uploadFolder.package}")
    private String uploadFolderPackage;

    public void createFile() throws Exception {
        // 获取修改记录信息文件 取当前版本号的数据
        String version = dicvalueService.getMaxValue(ReportWorldEnum.REPORT_VERSION.getCode());
        if (StringUtils.isBlank(version)) {
            throw new BusinessException("没有获取到版本号，请稍后重试！");
        }
        Map<String, String> mapFile = new HashMap<>();
        // 模块信息
        String modular = modularService.getModularJsonInfo();
        mapFile.put(ReportWorldFileNameEnum.MODULAR_JSON.getCode() + "." + ReportWorldFileNameEnum.MODULAR_JSON.getDesc(), modular);
        // 报表信息
        String report = reportService.getReportJsonInfo();
        mapFile.put(ReportWorldFileNameEnum.REPORT_JSON.getCode() + "." + ReportWorldFileNameEnum.REPORT_JSON.getDesc(), report);
        // 需求BUG文件
        String demandBugInfo = demandBugInfoService.getDemandBugJsonInfo();
        mapFile.put(ReportWorldFileNameEnum.DEMAND_BUG.getCode() + "." + ReportWorldFileNameEnum.DEMAND_BUG.getDesc(), demandBugInfo);
        //生成版本信息文件
        mapFile.put(ReportWorldFileNameEnum.VERSION.getCode() + "." + ReportWorldFileNameEnum.VERSION.getDesc(), version);
        // 报表世界升级工具数据对比策略信息,现在只存一条数据，以后有版本号可以按照版本号查询
        QueryWrapper<Compareconfig> compareconfigQueryWrapper = new QueryWrapper<>();
        Compareconfig compareconfig = compareconfigService.getOne(compareconfigQueryWrapper);
        if (null == compareconfig || StringUtils.isBlank(compareconfig.getCompareconfig())) {
            throw new BusinessException("获取升级工具对比数据策略信息失败，请稍后重试！");
        }
        mapFile.put(ReportWorldFileNameEnum.COMPARECONFIG.getCode() + "." + ReportWorldFileNameEnum.COMPARECONFIG.getDesc(), compareconfig.getCompareconfig());
        // 获取导出ZIP所需要的表结构，基础数据，SQL数据
        this.queryZipByData(mapFile);
        if (CollectionUtils.isEmpty(mapFile)) {
            throw new BusinessException("没有获取到要生成文件的信息，请稍后重试！");
        }
        for (Map.Entry<String, String> entry : mapFile.entrySet()) {
            FileWriter fileWriter = null;
            try {
                File fileSoure = new File(uploadFolderSoure);
                if (!fileSoure.exists()) {
                    fileSoure.mkdirs();
                    log.info("创建文件夹" + uploadFolderSoure);
                }
                fileWriter = new FileWriter(uploadFolderSoure + entry.getKey());
                fileWriter.write(entry.getValue());
            } catch (Exception e) {
                throw new BusinessException(entry.getKey() + "生成文件出错，请稍后重试！");
            } finally {
                fileWriter.flush();
                fileWriter.close();
            }
        }
    }

    /**
     * 获取导出ZIP所需要的表结构，基础数据，SQL数据
     *
     * @param mapFile
     */
    private void queryZipByData(Map<String, String> mapFile) throws Exception {
        if (CollectionUtils.isEmpty(mapFile)) {
            log.error("没有获取到存放数据的集合信息！");
            return;
        }
        long startTime = System.currentTimeMillis();
        // 获取客户关联信息
        Map<String, List<String>> mapDataCustomer = dataCustomerService.getDataCustomerMap();
        // 获取报表关联信息
        Map<String, List<String>> mapDataReport = dataReportService.getDataReportMap();
        // 获取模块关联信息
        Map<String, List<String>> mapDataModular = dataModularService.getDataModularMap();
        // 获取需求BUG关联信息
        Map<String, List<String>> mapDataDemandBug = dataDemandBugService.getDataDemandBugMap();
        this.getDataBaseInfoJson(mapDataCustomer, mapDataReport, mapDataModular, mapDataDemandBug, mapFile); //处理基础数据
        this.getDataSqlInfoJson(mapDataCustomer, mapDataReport, mapDataModular, mapDataDemandBug, mapFile); // 处理SQL脚本数据
        this.getTableInfoJson(mapDataCustomer, mapDataReport, mapDataModular, mapDataDemandBug, mapFile);// 处理表数据
        //任务执行总时长
        long times = System.currentTimeMillis() - startTime;
        System.out.println("  总共耗时：" + times / 1000 + "秒");
    }


    /**
     * 处理基础数据
     *
     * @param mapDataCustomer
     * @param mapDataReport
     * @param mapDataModular
     * @param mapDataDemandBug
     * @param mapFile
     */
    private void getDataBaseInfoJson(Map<String, List<String>> mapDataCustomer,
                                     Map<String, List<String>> mapDataReport,
                                     Map<String, List<String>> mapDataModular,
                                     Map<String, List<String>> mapDataDemandBug,
                                     Map<String, String> mapFile) throws Exception {
        // 基础数据
        Map<String, List<Object>> objectMap = databaseService.queryAllDataList();
        if (CollectionUtils.isEmpty(objectMap)) {
            log.error("没有获取到要导出的基础数据信息！");
            return;
        }
        // 获取每个数据类型对应code和主键字段,关联关系表都是存的code和主键
        Map<String, String> map = new HashMap();
        List<DatabaseConfig> listConfig = databaseConfigService.selectListDatabaseConfig();
        if (CollectionUtils.isEmpty(listConfig)) {
            log.error("没有获取到基础数据的配置信息！");
            return;
        }
        for (DatabaseConfig config : listConfig) {
            if (null == config) {
                continue;
            }
            map.put(config.getCode(), config.getPrimaryKeyColumn());
        }
        if (CollectionUtils.isEmpty(map)) {
            log.error("没有获取到基础数据的配置信息中基础数据主键字段信息！");
            return;
        }
        Map<String, String> josnMap = new HashMap();
        for (Map.Entry<String, List<Object>> entry : objectMap.entrySet()) { // 所有基础数据
            List<Object> list = entry.getValue();
            if (StringUtils.isBlank(entry.getKey()) || CollectionUtils.isEmpty(list)) {
                continue;
            }
            for (Object object : list) { // 一个类型的基础数据
                if (null == object) {
                    continue;
                }
                Map<String, Object> columMap = (Map<String, Object>) object; // 每一条数据
                if (CollectionUtils.isEmpty(columMap)) {
                    continue;
                }
                String primaryKeyColumn = map.get(entry.getKey());// 配置的主键字段
                if (StringUtils.isBlank(primaryKeyColumn)) {
                    continue;
                }
                Object primaryKeyValue = columMap.get(primaryKeyColumn); //主键的值
                if (null == primaryKeyValue || StringUtils.isBlank(primaryKeyValue.toString())) {
                    continue;
                }
                if (!CollectionUtils.isEmpty(mapDataModular)) {
                    columMap.put("listModular", mapDataModular.get(entry.getKey() + "\t" + primaryKeyValue));
                }
                if (!CollectionUtils.isEmpty(mapDataReport)) {
                    columMap.put("listReport", mapDataReport.get(entry.getKey() + "\t" + primaryKeyValue));
                }
                if (!CollectionUtils.isEmpty(mapDataCustomer)) {
                    columMap.put("listCustomer", mapDataCustomer.get(entry.getKey() + "\t" + primaryKeyValue));
                }
                if (!CollectionUtils.isEmpty(mapDataDemandBug)) {
                    columMap.put("listDemandBug", mapDataDemandBug.get(entry.getKey() + "\t" + primaryKeyValue));
                }
                // 每次导出的时候删除主键信息，主键是系统的
                columMap.remove(primaryKeyColumn);
            }
            String json = JSONObject.toJSONString(list, SerializerFeature.WriteMapNullValue);
            josnMap.put(entry.getKey().toUpperCase().replace("RW_DB_", ""), json);
        }
        String baseData = JSONObject.toJSONString(josnMap, SerializerFeature.WriteMapNullValue);
        mapFile.put(ReportWorldFileNameEnum.DATABASE_JSON.getCode() + "." + ReportWorldFileNameEnum.DATABASE_JSON.getDesc(), baseData);
    }

    /**
     * 处理SQL数据
     *
     * @param mapDataCustomer
     * @param mapDataReport
     * @param mapDataModular
     * @param mapDataDemandBug
     * @param mapFile
     */
    private void getDataSqlInfoJson(Map<String, List<String>> mapDataCustomer,
                                    Map<String, List<String>> mapDataReport,
                                    Map<String, List<String>> mapDataModular,
                                    Map<String, List<String>> mapDataDemandBug,
                                    Map<String, String> mapFile) throws Exception {
        // sql信息
        QueryWrapper<DataSql> dataSqlQueryWrapper = new QueryWrapper<>();
        dataSqlQueryWrapper.in("STATUS", ReportWorldStatusEnum.getUpgradeToolsZipStatus());
        List<DataSql> dataSqlList = dataSqlService.list(dataSqlQueryWrapper);
        if (CollectionUtils.isEmpty(dataSqlList)) {
            log.error("没有获取到SQL脚本相关信息！");
            return;
        }
        List<DataSqlVO> listvo = new ArrayList<>();
        for (DataSql dataSql : dataSqlList) {
            if (null == dataSql || StringUtils.isBlank(dataSql.getId())) {
                continue;
            }
            DataSqlVO vo = new DataSqlVO();
            BeanUtils.copyProperties(dataSql, vo);
            if (!CollectionUtils.isEmpty(mapDataModular)) {
                vo.setListModular(mapDataModular.get(ReportWorldEnum.REPORT_DATASQL_CODE.getCode() + "\t" + dataSql.getId()));
            }
            if (!CollectionUtils.isEmpty(mapDataReport)) {
                vo.setListReport(mapDataReport.get(ReportWorldEnum.REPORT_DATASQL_CODE.getCode() + "\t" + dataSql.getId()));
            }
            if (!CollectionUtils.isEmpty(mapDataCustomer)) {
                vo.setListCustomer(mapDataCustomer.get(ReportWorldEnum.REPORT_DATASQL_CODE.getCode() + "\t" + dataSql.getId()));
            }
            if (!CollectionUtils.isEmpty(mapDataDemandBug)) {
                vo.setListDemandBug(mapDataDemandBug.get(ReportWorldEnum.REPORT_DATASQL_CODE.getCode() + "\t" + dataSql.getId()));
            }
            listvo.add(vo);
        }
        String json = JSONObject.toJSONString(listvo, SerializerFeature.WriteMapNullValue);
        mapFile.put(ReportWorldFileNameEnum.SQL_JSON.getCode() + "." + ReportWorldFileNameEnum.SQL_JSON.getDesc(), json);
    }


    /**
     * 处理表数据信息，包含表的索引，和字段信息
     *
     * @param mapDataCustomer
     * @param mapDataReport
     * @param mapDataModular
     * @param mapDataDemandBug
     * @param mapFile
     */
    private void getTableInfoJson(Map<String, List<String>> mapDataCustomer,
                                  Map<String, List<String>> mapDataReport,
                                  Map<String, List<String>> mapDataModular,
                                  Map<String, List<String>> mapDataDemandBug,
                                  Map<String, String> mapFile) throws Exception {
        // 表结构信息
        QueryWrapper<Table> tableQueryWrapper = new QueryWrapper<>();
        tableQueryWrapper.in("STATUS", ReportWorldStatusEnum.getUpgradeToolsZipStatus());
        List<Table> tableList = tableService.list(tableQueryWrapper);
        Map<String, List<TableDetailVO>> mapTableDetail = this.queryTableDetailVoMap(mapDataCustomer, mapDataReport, mapDataModular, mapDataDemandBug); // 获取表字段信息
        if (CollectionUtils.isEmpty(mapTableDetail)) {
            throw new BusinessException("没有获取到表字段信息，请检查表结构信息！");
        }
        Map<String, List<TableIndexedVO>> mapTableIndexedVo = this.queryTableIndexedVoMap();// 获取表索引信息
        List<TableVO> listVo = new ArrayList<>();
        for (Table table : tableList) {
            if (null == table || StringUtils.isBlank(table.getId())) {
                continue;
            }
            TableVO vo = new TableVO();
            BeanUtils.copyProperties(table, vo);
            // 表字段信息 没有字段信息的表跳过
            if (!mapTableDetail.containsKey(table.getId()) || CollectionUtils.isEmpty(mapTableDetail.get(table.getId()))) {
                log.error(table.getName() + "没有获取到字段信息！");
                throw new BusinessException(table.getName() + "没有获取到字段信息，请检查表字段信息！");
            }
            vo.setListTableDetail(mapTableDetail.get(table.getId()));
            if (!CollectionUtils.isEmpty(mapDataModular)) {
                vo.setListModular(mapDataModular.get(ReportWorldEnum.REPORT_TABLE_CODE.getCode() + "\t" + table.getId()));
            }
            if (!CollectionUtils.isEmpty(mapDataReport)) {
                vo.setListReport(mapDataReport.get(ReportWorldEnum.REPORT_TABLE_CODE.getCode() + "\t" + table.getId()));
            }
            if (!CollectionUtils.isEmpty(mapDataCustomer)) {
                vo.setListCustomer(mapDataCustomer.get(ReportWorldEnum.REPORT_TABLE_CODE.getCode() + "\t" + table.getId()));
            }
            if (!CollectionUtils.isEmpty(mapDataDemandBug)) {
                vo.setListDemandBug(mapDataDemandBug.get(ReportWorldEnum.REPORT_TABLE_CODE.getCode() + "\t" + table.getId()));
            }
            if (!CollectionUtils.isEmpty(mapTableIndexedVo)) {
                vo.setListIndexed(mapTableIndexedVo.get(table.getId()));
            }
            listVo.add(vo);
        }
        String json = JSONObject.toJSONString(listVo, SerializerFeature.WriteMapNullValue);
        mapFile.put(ReportWorldFileNameEnum.REPORT_TABLE_FILENAME_JSON.getCode() + "."
                + ReportWorldFileNameEnum.REPORT_TABLE_FILENAME_JSON.getDesc(), json);
    }

    /**
     * 获取表字段信息
     *
     * @param mapDataCustomer
     * @param mapDataReport
     * @param mapDataModular
     * @param mapDataDemandBug
     */
    private Map<String, List<TableDetailVO>> queryTableDetailVoMap(Map<String, List<String>> mapDataCustomer,
                                                                   Map<String, List<String>> mapDataReport,
                                                                   Map<String, List<String>> mapDataModular,
                                                                   Map<String, List<String>> mapDataDemandBug) throws Exception {
        // 表字段信息
        QueryWrapper<TableDetail> tableDetailQueryWrapper = new QueryWrapper<>();
        tableDetailQueryWrapper.in("STATUS", ReportWorldStatusEnum.getUpgradeToolsZipStatus());
        List<TableDetail> tableDetailList = tableDetailService.list(tableDetailQueryWrapper);
        if (CollectionUtils.isEmpty(tableDetailList)) {
            log.error("没有获取到表字段信息！");
            return null;
        }
        // 表字段处理
        Map<String, List<TableDetailVO>> mapTableDetail = new HashMap();
        for (TableDetail detail : tableDetailList) {
            if (null == detail || StringUtils.isBlank(detail.getTableId())) {
                continue;
            }
            TableDetailVO detailVO = new TableDetailVO();
            BeanUtils.copyProperties(detail, detailVO);
            if (!CollectionUtils.isEmpty(mapDataModular)) {
                detailVO.setListModular(mapDataModular.get(ReportWorldEnum.REPORT_TABLE_DETAIL_CODE.getCode() + "\t" + detail.getId()));
            }
            if (!CollectionUtils.isEmpty(mapDataReport)) {
                detailVO.setListReport(mapDataReport.get(ReportWorldEnum.REPORT_TABLE_DETAIL_CODE.getCode() + "\t" + detail.getId()));
            }
            if (!CollectionUtils.isEmpty(mapDataCustomer)) {
                detailVO.setListCustomer(mapDataCustomer.get(ReportWorldEnum.REPORT_TABLE_DETAIL_CODE.getCode() + "\t" + detail.getId()));
            }
            if (!CollectionUtils.isEmpty(mapDataDemandBug)) {
                detailVO.setListDemandBug(mapDataDemandBug.get(ReportWorldEnum.REPORT_TABLE_DETAIL_CODE.getCode() + "\t" + detail.getId()));
            }
            if (mapTableDetail.containsKey(detailVO.getTableId())) {
                List<TableDetailVO> list = mapTableDetail.get(detailVO.getTableId());
                list.add(detailVO);
                mapTableDetail.put(detail.getTableId(), list);
            } else {
                List<TableDetailVO> list = new ArrayList<>();
                list.add(detailVO);
                mapTableDetail.put(detailVO.getTableId(), list);
            }
        }
        return mapTableDetail;
    }

    /**
     * 获取表的索引信息
     *
     * @return
     */
    private Map<String, List<TableIndexedVO>> queryTableIndexedVoMap() throws Exception {
        // 索引信息
        Map<String, List<TableIndexed>> mapTableIndexed = tableIndexedService.getTableIndexedMap();
        if (CollectionUtils.isEmpty(mapTableIndexed)) {
            return null;
        }
        // 索引处理成JSON格式需要的
        Map<String, List<TableIndexedVO>> mapTableIndexedVo = new HashMap();
        for (Map.Entry<String, List<TableIndexed>> entry : mapTableIndexed.entrySet()) {
            List<TableIndexed> list = entry.getValue();
            Map<String, TableIndexedVO> mapIndexVo = new LinkedHashMap<>();
            for (TableIndexed indexed : list) {
                if (mapIndexVo.containsKey(indexed.getIndexedName())) { // 存在索引名称的
                    TableIndexedVO vo = mapIndexVo.get(indexed.getIndexedName());
                    String columnName = indexed.getIndexedColumnName()
                            + (StringUtils.isNotBlank(indexed.getIndexedAscDesc()) ? " " + indexed.getIndexedAscDesc() : "");
                    vo.setIndexColumnName(vo.getIndexColumnName() + "," + columnName);
                    mapIndexVo.put(indexed.getIndexedName(), vo);
                } else {
                    TableIndexedVO vo = new TableIndexedVO();
                    String columnName = indexed.getIndexedColumnName()
                            + (StringUtils.isNotBlank(indexed.getIndexedAscDesc()) ? " " + indexed.getIndexedAscDesc() : "");
                    vo.setIndexColumnName(columnName);
                    vo.setIndexType(indexed.getIndexedType());
                    vo.setStatus(indexed.getStatus());
                    vo.setIndexName(indexed.getIndexedName());
                    mapIndexVo.put(indexed.getIndexedName(), vo);
                }
            }
            List<TableIndexedVO> listvo = new ArrayList<>();
            for (Map.Entry<String, TableIndexedVO> entryVo : mapIndexVo.entrySet()) {
                if (null == entryVo.getValue()) {
                    continue;
                }
                listvo.add(entryVo.getValue());
            }
            mapTableIndexedVo.put(entry.getKey(), listvo);
        }
        return mapTableIndexedVo;
    }

    /**
     * 导出ZIP文件
     *
     * @param response
     * @throws Exception
     */
    public void downloadZipFile(HttpServletResponse response) throws Exception {
        // 获取现在最大的版本号
        String version = dicvalueService.getMaxValue(ReportWorldEnum.REPORT_VERSION.getCode());
        if (StringUtils.isBlank(version)) {
            throw new BusinessException("没有获取到版本号，请稍后重试！");
        }
        String fileName = "bbsj_" + version + "." + YssEnum.YSS_ZIP.getCode();
        // ZipUtil.zipDateFile(response, uploadFolder, fileName);
        // 创建存放压缩文件的路径
        File fileSoure = new File(uploadFolder);
        if (!fileSoure.exists()) {
            fileSoure.mkdirs();
            log.info("创建文件夹" + uploadFolder);
        }
        String zipName = uploadFolder + fileName; // ZIP生成路径
        // 生成ZIP 按照文件夹压缩
        ZipUtil.zipFolder(Paths.get(uploadFolderPackage), Paths.get(zipName));
        FileWriterUtil.downloadFile(response, zipName); //下载完成后删除了文件
        // 删除ZIP文件生成文件夹
        File file = new File(uploadFolder);
        FileUtils.deleteDirectory(file);
        // 删除打包文件下的文件夹
        File fileFolderPackage = new File(uploadFolderPackage);
        FileUtils.deleteDirectory(fileFolderPackage);
    }

}
